package com.sunkyc.framework.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunkyc.commons.contants.GlobContants;
import com.sunkyc.commons.entity.TablePageData;
import com.sunkyc.commons.exception.CustomerException;
import com.sunkyc.framework.system.CacheKey.AuthroticationCacheKeys;
import com.sunkyc.framework.system.entity.*;
import com.sunkyc.framework.system.entity.vo.UpdatePasswordVo;
import com.sunkyc.framework.system.mapper.SysUserMapper;
import com.sunkyc.framework.system.service.SysDeptService;
import com.sunkyc.framework.system.service.SysRoleService;
import com.sunkyc.framework.system.service.SysUserRoleService;
import com.sunkyc.framework.system.service.SysUserService;
import com.sunkyc.framework.utils.RedisUtils;
import com.sunkyc.framework.utils.TablePageDataBuilderUtil;
import com.sunkyc.commons.entity.PageQueryVo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author sunkyc
 * @since 2022-05-31
 */
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
    private final SysUserMapper baseMapper;

    private final SysUserRoleService userRoleService;
    private final RedisUtils redisUtils;

    /**
     * 默认头像
     */
    @Value("${system.defaultavatar}")
    private String defaultavatar;


    @Override
    public TablePageData<SysUser> queryList(PageQueryVo pageQueryVo, SysUser sysUser) {
        Wrapper<SysUser> wrapper = buildWrapper(sysUser);
        Page<SysUser> page = new Page<>(pageQueryVo.getCurrent(), pageQueryVo.getPageSize());
        IPage<SysUser> iPage = baseMapper.selectPage(page, wrapper);
        if (CollectionUtils.isNotEmpty(iPage.getRecords())) {
            // 这里采用获取的方式：如果采用自动注入会出现循环依赖bug
            SysDeptService sysDeptService = SpringUtil.getBean(SysDeptService.class);
            for (SysUser user : iPage.getRecords()) {
                //SysUserRole userRole = userRoleService.getOne(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, user.getUserId()));
                user.setRoleIds(userRoleService.queryRoleIdsByUserId(user.getUserId()));
                user.setDeptStr(sysDeptService.getById(user.getDeptId()).getDeptName());
            }
        }
        TablePageData<SysUser> pageData = TablePageDataBuilderUtil.buildTablePageData(iPage);
        return pageData;
    }

    @Override
    public Boolean checkedUserNameUnique(SysUser user) {
        if (StringUtils.isBlank(user.getUserName())) return true;
        return baseMapper.exists(
                Wrappers.lambdaQuery(SysUser.class)
                        .eq(SysUser::getUserName, user.getUserName())
                        .ne(ObjectUtils.isNotEmpty(user.getUserId()), SysUser::getUserId, user.getUserId())
        );
    }

    @Override
    public Boolean checkedPhoneUnique(SysUser user) {
        if (StringUtils.isBlank(user.getPhonenumber())) return true;
        return baseMapper.exists(
                Wrappers.lambdaQuery(SysUser.class)
                        .eq(SysUser::getPhonenumber, user.getPhonenumber())
                        .ne(ObjectUtils.isNotEmpty(user.getUserId()), SysUser::getUserId, user.getUserId())
        );
    }

    @Override
    public Boolean checkedEmailUnique(SysUser user) {
        if (StringUtils.isBlank(user.getEmail())) return true;
        return baseMapper.exists(
                Wrappers.lambdaQuery(SysUser.class)
                        .eq(SysUser::getEmail, user.getEmail())
                        .ne(ObjectUtils.isNotEmpty(user.getUserId()), SysUser::getUserId, user.getUserId())
        );
    }

    @Override
    public SysUser queryById(Long userId) {
        SysUser sysUser = baseMapper.selectById(userId);
        if (ObjectUtils.isNotEmpty(sysUser)) {
            sysUser.setPwd(null);
            List<SysUserRole> userRoles = userRoleService.list(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, sysUser.getUserId()));
            if (CollectionUtils.isNotEmpty(userRoles)) {
                sysUser.setRoleIds(userRoleService.queryRoleIdsByUserId(sysUser.getUserId()));
                sysUser.setDeptStr(SpringUtil.getBean(SysDeptService.class).getById(sysUser.getDeptId()).getDeptName());
            }
        }
        return sysUser;
    }

    @Override
    @Transactional
    public int addUser(SysUser user) {
        user.setPwd(BCrypt.hashpw(GlobContants.INIT_PASSWORD));
        user.setAvatar(defaultavatar);
        int count = baseMapper.insert(user);
        if (count > 0) {
            if (CollectionUtils.isNotEmpty(user.getRoleIds())) {
                for (Long roleId : user.getRoleIds()) {
                    if(GlobContants.SUPER_ADMIN_USER_AND_ROLE_ID.equals(roleId)){
                        throw new CustomerException("超级管理员无法被添加");
                    }
                    userRoleService.save(new SysUserRole().setUserId(user.getUserId()).setRoleId(roleId));
                }
            }
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        }
        return count;
    }

    @Override
    @Transactional
    public int delUser(Long[] ids) {
        int count = baseMapper.deleteBatchIds(Arrays.asList(ids));
        if (count > 0) {
            for (Long id : ids) {
                if(GlobContants.SUPER_ADMIN_USER_AND_ROLE_ID.equals(id)){
                    throw new CustomerException("超级管理员无法被删除");
                }
                userRoleService.remove(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, id));
            }
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        }
        return count;
    }

    @Override
    public int updateUser(SysUser user) {
        if(GlobContants.SUPER_ADMIN_USER_AND_ROLE_ID.equals(user.getUserId())){
            throw new CustomerException("超级管理员无法被修改");
        }
        int count = baseMapper.updateById(user);
        if (count > 0) {
            userRoleService.remove(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, user.getUserId()));
            for (Long roleId : user.getRoleIds()) {
                if(GlobContants.SUPER_ADMIN_USER_AND_ROLE_ID.equals(roleId)){
                    throw new CustomerException("超级管理员无法被修改");
                }
                userRoleService.save(new SysUserRole().setUserId(user.getUserId()).setRoleId(roleId));
            }
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        }
        return count;
    }

    @Override
    public int restPwd(SysUser user) {
        if(GlobContants.SUPER_ADMIN_USER_AND_ROLE_ID.equals(user.getUserId())){
            throw new CustomerException("超级管理员无法被修改");
        }
        user.setPwd(BCrypt.hashpw(GlobContants.INIT_PASSWORD));
        int count = baseMapper.updateById(user);
        return count;
    }

    @Override
    public LoginUserInfoVo getUserInfo(Long userId) {
        SysUser user = queryById(userId);
        if (ObjectUtil.isEmpty(user)) return null;
        SysDeptService sysDeptService = SpringUtil.getBean(SysDeptService.class);
        LoginUserInfoVo userInfoVo = new LoginUserInfoVo()
                .setAvatar(user.getAvatar())
                .setNickName(user.getNickName())
                .setLastLoginIp(user.getLoginIp())
                .setLastLoginTime(user.getLoginDate())
                .setUsername(user.getUserName());
        SysDept dept = sysDeptService.getById(user.getDeptId());
        userInfoVo.setDeptName(ObjectUtil.isEmpty(dept)?"暂无组织":dept.getDeptName());
        List<Long> roleIds = user.getRoleIds();
        if(CollectionUtils.isNotEmpty(roleIds)){
            List<String> roleNames= new ArrayList<>();
            SysRoleService roleService = SpringUtil.getBean(SysRoleService.class);
            for (Long roleId : roleIds) {
                SysRole sysRole = roleService.getById(roleId);
                if(ObjectUtil.isNotEmpty(sysRole)){
                    roleNames.add(sysRole.getRoleName());
                }
            }
            String s = roleNames.toString().replaceAll(",", "").replaceAll("\\[","").replaceAll("\\]","");
            userInfoVo.setRoleNames(s);
        }
        return userInfoVo;
    }

    @Override
    public SysUser getUserInfoByUserName(String username) {
        return baseMapper.getUserInfoByUserName(username);
    }

    @Override
    public int updatePwd(long currentId, UpdatePasswordVo updatePasswordVo) {
        SysUser user = baseMapper.selectById(currentId);
        if(ObjectUtil.isEmpty(user)) throw new CustomerException("密码修改失败，请重试！");
        if(!BCrypt.checkpw(updatePasswordVo.getOldPwd(),user.getPwd())){
            throw new CustomerException("密码修改失败，请重试！");
        }

        user.setPwd(BCrypt.hashpw(updatePasswordVo.getNewPwd()));
        return  baseMapper.updateById(user);
    }

    @Override
    public int resetAvatar(long currentId, String avatar) {
        SysUser user = baseMapper.selectById(currentId);
        if(ObjectUtil.isEmpty(user)) throw new CustomerException("头像修改失败！");
        user.setAvatar(avatar);
        return  baseMapper.updateById(user);
    }

    private Wrapper<SysUser> buildWrapper(SysUser sysUser) {
        LambdaQueryWrapper<SysUser> wrapper = Wrappers.lambdaQuery(SysUser.class);
        wrapper.like(StringUtils.isNotBlank(sysUser.getUserName()), SysUser::getUserName, sysUser.getUserName())
                .eq(StringUtils.isNotBlank(sysUser.getPhonenumber()), SysUser::getPhonenumber, sysUser.getPhonenumber())
                //.eq(SysUser::getState, StringUtils.isNotBlank(sysUser.getState()) ? sysUser.getState() : GlobContants.COMMON_STATUS_NORMAL)
                .eq(StringUtils.isNotBlank(sysUser.getState()), SysUser::getState, sysUser.getState())
                .eq(StringUtils.isBlank(sysUser.getState()), SysUser::getState, GlobContants.COMMON_STATUS_NORMAL);
        if (ObjectUtil.isNotNull(sysUser.getDeptId())) {
            wrapper.in(SysUser::getDeptId, queryDeptIds(sysUser.getDeptId()));
        }
        wrapper
                .select(SysUser.class, info ->
                        !info.getColumn().equals("pwd") &&
                                !info.getColumn().equals("create_by") &&
                                !info.getColumn().equals("update_by") &&
                                !info.getColumn().equals("update_time")
                );
        return wrapper;
    }


    private List<Long> queryDeptIds(Long deptId) {
        return SpringUtil.getBean(SysDeptService.class).querySelfAndChildrenIds(deptId);
    }

}
